
#include "member_BCylinder.h"

using namespace BWE;

member_BCylinder::member_BCylinder(BCylinder* cylinder)
{
	boss = cylinder;
	radius = 0;
	height = 0;
	sides = 0;
	segments = 1;
	radiusSegments = 1;
}
member_BCylinder::~member_BCylinder()
{

}

void member_BCylinder::prepare()
{
	if (sines.size() != sides)
	{
		sines.resize(sides);
		coses.resize(sides);
		float sr = PI2 / sides;
		for (int i = 0; i < sides; i++)
		{
			double angle = i * sr;
			coses[i] = cos(angle);
			sines[i] = sin(angle);
		}
	}
}

void member_BCylinder::rebuild()
{
	int flankNumVerts = sides * (segments + 1);
	int topNumVerts = sides * (radiusSegments - 1) + 1;
	int bottomNumVerts = topNumVerts;
	int totalNumVerts = flankNumVerts + topNumVerts + bottomNumVerts;

	BVectorArray* vertices = boss->vertices();
	BVectorArray* normals = boss->normals();
	if (!vertices || vertices->size() != totalNumVerts)
	{
		vertices = new BVectorArray(totalNumVerts);
		normals = new BVectorArray(totalNumVerts);
		boss->setVertices(vertices);
		boss->setNormals(normals);
	}

	boss->clearPrimitives();

	float sz = height / segments;
	float stx = 1.0f / sides;
	float sty = 1.0f / segments;
	float sr = PI2 / sides;

	//make flank vertices.
	for (int r = 0; r < segments + 1; r++)
	{
		float z = sz * r;
		float ty = sty * r;
		int head = r * sides;
		for (int c = 0; c < sides; c++)
		{
			float nx = coses[c];
			float ny = sines[c];
			vertices->set(head + c, BVector(nx * radius, ny * radius, z));
			normals->set(head + c, BVector(nx, ny, 0));
		}
	}

	//make bottom and top vertices.
	if (radiusSegments > 0)
	{
		float real_radius = radius;
		float step_radius = radius / radiusSegments;
		for (int r = 0; r < radiusSegments - 1; r++)
		{
			real_radius -= step_radius;
			int head = flankNumVerts + r * sides;
			for (int c = 0; c < sides; c++)
			{
				float x = coses[c] * real_radius;
				float y = sines[c] * real_radius;
				(*vertices)[head + c] = BVector(x, y, 0);
				(*normals)[head + c] = BVector(0, 0, -1);
			}
		}
		int center_index = flankNumVerts + bottomNumVerts - 1;
		(*vertices)[center_index] = BVector(0, 0, 0);
		(*normals)[center_index] = BVector(0, 0, -1);

		int bottom_begin = flankNumVerts;
		int top_begin = flankNumVerts + bottomNumVerts;
		for (int i = 0; i < topNumVerts; i++)
		{
			(*vertices)[top_begin + i] = (*vertices)[bottom_begin + i] + BVector(0, 0, height);
			(*normals)[top_begin + i] = BVector(0, 0, 1);
		}
	}

	BIndexArray* flankIndices = new BIndexArray(segments * sides * 4);
	BPrimitive* flankPrimitive = new BPrimitive(BPrimitive::Quads, flankIndices);
	int fi = 0;
	for (int r = 0; r < segments; r++)
	{
		int head = r * sides;
		int pos = r * sides * 4;
		for (int c = 0; c < sides; c++)
		{
			int index0 = head + c;
			int index1 = head + (c + 1) % sides;
			int index2 = index0 + sides;
			int index3 = index1 + sides;
			(*flankIndices)[pos + c * 4] = index0;
			(*flankIndices)[pos + c * 4 + 1] = index1;
			(*flankIndices)[pos + c * 4 + 2] = index3;
			(*flankIndices)[pos + c * 4 + 3] = index2;
		}
	}
	boss->addPrimitive(flankPrimitive);

	if (radiusSegments < 1)
	{
		BIndexArray* topIndices = new BIndexArray(sides);
		BPrimitive* topPrimitive = new BPrimitive(BPrimitive::Polygon, topIndices);
		int start = flankNumVerts - sides;
		for (int i = 0; i < sides; i++)
		{
			(*topIndices)[i] = start + i;
		}
		boss->addPrimitive(topPrimitive);
	}
	if (radiusSegments == 1)
	{
		BIndexArray* topCentralIndices = new BIndexArray(sides * 3);
		BPrimitive* topCentralPrimitive = new BPrimitive(BPrimitive::Triangles, topCentralIndices);
		int head0 = flankNumVerts - sides;
		int center = flankNumVerts + bottomNumVerts;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head0 + i;
			int index1 = head0 + (i + 1) % sides;
			(*topCentralIndices)[i * 3] = index0;
			(*topCentralIndices)[i * 3 + 1] = index1;
			(*topCentralIndices)[i * 3 + 2] = center;
		}
		boss->addPrimitive(topCentralPrimitive);
	}
	if (radiusSegments > 1)
	{
		BIndexArray* topIndices = new BIndexArray((radiusSegments - 1) * sides * 4);
		BPrimitive* topPrimitive = new BPrimitive(BPrimitive::Quads, topIndices);

		int head0 = flankNumVerts - sides;
		int head1 = flankNumVerts + bottomNumVerts;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head0 + i;
			int index1 = head0 + (i + 1) % sides;
			int index2 = head1 + i;
			int index3 = head1 + (i + 1) % sides;
			(*topIndices)[i * 4] = index0;
			(*topIndices)[i * 4 + 1] = index1;
			(*topIndices)[i * 4 + 2] = index3;
			(*topIndices)[i * 4 + 3] = index2;
		}
		for (int r = 0; r < radiusSegments - 2; r++)
		{
			int head = flankNumVerts + bottomNumVerts + sides * r;
			int pos = sides * 4 + r * sides * 4;
			for (int c = 0; c < sides; c++)
			{
				int index0 = head + c;
				int index1 = head + (c + 1) % sides;
				int index2 = index0 + sides;
				int index3 = index1 + sides;
				(*topIndices)[pos + c * 4] = index0;
				(*topIndices)[pos + c * 4 + 1] = index1;
				(*topIndices)[pos + c * 4 + 2] = index3;
				(*topIndices)[pos + c * 4 + 3] = index2;
			}
		}
		boss->addPrimitive(topPrimitive);
		//build top central circle;
		BIndexArray* topCentralIndices = new BIndexArray(sides * 3);
		BPrimitive* topCentralPrimitive = new BPrimitive(BPrimitive::Triangles, topCentralIndices);
		int center = flankNumVerts + bottomNumVerts + topNumVerts - 1;
		int head = center - sides;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head + i;
			int index1 = head + (i + 1) % sides;
			(*topCentralIndices)[i * 3] = index0;
			(*topCentralIndices)[i * 3 + 1] = index1;
			(*topCentralIndices)[i * 3 + 2] = center;
		}
		boss->addPrimitive(topCentralPrimitive);
	}

	if (radiusSegments < 1)
	{
		BIndexArray* bottomIndices = new BIndexArray(sides);
		BPrimitive* bottomPrimitive = new BPrimitive(BPrimitive::Polygon, bottomIndices);
		for (int i = 0; i < sides; i++)
		{
			(*bottomIndices)[i] = sides - i - 1;
		}
		boss->addPrimitive(bottomPrimitive);
	}
	if (radiusSegments == 1)
	{
		BIndexArray* bottomCentralIndices = new BIndexArray(sides * 3);
		BPrimitive* bottomCentralPrimitive = new BPrimitive(BPrimitive::Triangles, bottomCentralIndices);
		int head0 = 0;
		int center = flankNumVerts;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head0 + i;
			int index1 = head0 + (i + 1) % sides;
			(*bottomCentralIndices)[i * 3] = index0;
			(*bottomCentralIndices)[i * 3 + 1] = index1;
			(*bottomCentralIndices)[i * 3 + 2] = center;
		}
		boss->addPrimitive(bottomCentralPrimitive);
	}
	if (radiusSegments > 1)
	{
		BIndexArray* bottomIndices = new BIndexArray((radiusSegments - 1) * sides * 4);
		BPrimitive* bottomPrimitive = new BPrimitive(BPrimitive::Quads, bottomIndices);

		int head0 = 0;
		int head1 = flankNumVerts;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head0 + i;
			int index1 = head0 + (i + 1) % sides;
			int index2 = head1 + i;
			int index3 = head1 + (i + 1) % sides;
			(*bottomIndices)[i * 4] = index0;
			(*bottomIndices)[i * 4 + 1] = index2;
			(*bottomIndices)[i * 4 + 2] = index3;
			(*bottomIndices)[i * 4 + 3] = index1;
		}

		for (int r = 0; r < radiusSegments - 2; r++)
		{
			int head = flankNumVerts + sides * r;
			int pos = sides * 4 + r * sides * 4;
			for (int c = 0; c < sides; c++)
			{
				int index0 = head + c;
				int index1 = head + (c + 1) % sides;
				int index2 = index0 + sides;
				int index3 = index1 + sides;
				(*bottomIndices)[pos + c * 4] = index0;
				(*bottomIndices)[pos + c * 4 + 1] = index2;
				(*bottomIndices)[pos + c * 4 + 2] = index3;
				(*bottomIndices)[pos + c * 4 + 3] = index1;
			}
		}
		boss->addPrimitive(bottomPrimitive);

		//build top central circle;
		BIndexArray* bottomCentralIndices = new BIndexArray(sides * 3);
		BPrimitive* bottomCentralPrimitive = new BPrimitive(BPrimitive::Triangles, bottomCentralIndices);
		int center = flankNumVerts + bottomNumVerts - 1;
		int head = center - sides;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head + i;
			int index1 = head + (i + 1) % sides;
			(*bottomCentralIndices)[i * 3] = index0;
			(*bottomCentralIndices)[i * 3 + 1] = center;
			(*bottomCentralIndices)[i * 3 + 2] = index1;
		}
		boss->addPrimitive(bottomCentralPrimitive);

	}
}
